using System;
using System.Collections;
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
using UniVRM10;

public class VEmotionController : MonoBehaviour
{
    public AvatarType avatarType;
    private Vrm10Instance vrm10Instance;
    private Vrm10RuntimeExpression expression;
    private void Reset()
    {
        var vrminstance = gameObject.GetComponent<Vrm10Instance>();
        if (vrminstance != null) avatarType = AvatarType.VRM;
        else avatarType = AvatarType.FBX_Human;
    }
    private void Start()
    {
        if (avatarType == AvatarType.VRM)
        {
            vrm10Instance = GetComponent<Vrm10Instance>();
            expression = vrm10Instance.Runtime.Expression;
        }

        m_AudioSource = GetComponent<AudioSource>();
        if (Context == 0)
        {
            if (OVRLipSync.CreateContext(ref Context, provider, 0, enableAcceleration)
                != OVRLipSync.Result.Success)
            {
                Debug.LogError("OVRLipSyncContextBase.Start ERROR: Could not create" +
                    " Phoneme context.");
                return;
            }
        }
        meshRenderer = transform.UniqueChild("Face").GetComponent<SkinnedMeshRenderer>();
        InitExpressionKey();
        SetupBlink();
    }
    public void Show(ExpressionKey expressionKey, float normalizedWeight = 1)
    {
        if (avatarType == AvatarType.VRM)
        {
            expression.SetWeight(expressionKey, normalizedWeight);
        }
    }

    [Tooltip("Which lip sync provider to use for viseme computation.")]
    public OVRLipSync.ContextProviders provider = OVRLipSync.ContextProviders.Enhanced;
    [Tooltip("Enable DSP offload on supported Android devices.")]
    public bool enableAcceleration = true;
    [BoxGroup("Blink")]
    [LabelText("开启眨眼")]
    public bool enableBlink = true;
    [BoxGroup("Blink")]
    public float blinkFrequency = 4;
    private uint Context = 0;
    private AudioSource m_AudioSource;
    private SkinnedMeshRenderer meshRenderer;
    private float blendWeightMultiplier = 100f;
    public VisemeBlenderShapeIndexMap m_VisemeIndex;
    private OVRLipSync.Frame frame = new OVRLipSync.Frame();
    protected OVRLipSync.Frame Frame => frame;
    void OnAudioFilterRead(float[] data, int channels)
    {
        ProcessAudioSamplesRaw(data, channels);
    }
    public void ProcessAudioSamplesRaw(float[] data, int channels)
    {
        lock (this)
        {
            if (OVRLipSync.IsInitialized() != OVRLipSync.Result.Success)
            {
                return;
            }
            var frame = this.Frame;
            OVRLipSync.ProcessFrame(Context, data, frame, channels == 2);
        }
    }

    private void Update()
    {
        if (this.Frame == null) return;

        if (avatarType == AvatarType.VRM)
        {
            SetLipsExpressionKey();
        }
    }
    [Button]
    private void SetupBlink()
    {
        if (!enableBlink) return;
        Action<float> blink = (weight) => expression.SetWeight(ExpressionKey.Blink, weight);

        TObserver blinkLooper = new TObserver()
        {
            end = ()=>blink.Round(0, 1, 0.2f),
            duration = blinkFrequency,
            loopCount = -1
        }.Subscribe();
    }
    private void SetBlenderShapes()
    {
        for (int i = 0; i < this.Frame.Visemes.Length; i++)
        {
            string _name = ((OVRLipSync.Viseme)i).ToString();
            int blendShapeIndex = GetBlenderShapeIndexByName(_name);
            int blendWeight = (int)(blendWeightMultiplier * this.Frame.Visemes[i]);
            if (blendShapeIndex == 999)
                continue;

            meshRenderer.SetBlendShapeWeight(blendShapeIndex, blendWeight);
        }
    }

    private void SetLipsExpressionKey()
    {
        for (int i = 0; i < this.Frame.Visemes.Length; i++)
        {
            var key = VisemeToExpressionKey((OVRLipSync.Viseme)i);
            expression.SetWeight(key, Frame.Visemes[i]);
        }
    }


    private int GetBlenderShapeIndexByName(string _name)
    {
        if (_name == "sil")
        {
            return 999;
        }
        if (_name == "aa")
        {
            return m_VisemeIndex.A;
        }
        if (_name == "ih")
        {
            return m_VisemeIndex.I;
        }
        if (_name == "E")
        {
            return m_VisemeIndex.E;
        }
        if (_name == "oh")
        {
            return m_VisemeIndex.O;
        }

        return m_VisemeIndex.U;
    }

    [System.Serializable]
    public class VisemeBlenderShapeIndexMap
    {
        public int A;
        public int I;
        public int U;
        public int E;
        public int O;

    }


    private ExpressionKey Neutral;
    private ExpressionKey Aa;
    private ExpressionKey Ih;
    private ExpressionKey Ou;
    private ExpressionKey Ee;
    private ExpressionKey Oh;
    private void InitExpressionKey()
    {
        Aa = ExpressionKey.Aa;
        Ih = ExpressionKey.Ih;
        Ou = ExpressionKey.Ou;
        Ee = ExpressionKey.Ee;
        Oh = ExpressionKey.Oh;
        Neutral = ExpressionKey.Neutral;
    }

    private ExpressionKey VisemeToExpressionKey(OVRLipSync.Viseme viseme)
    {
        return viseme switch
        {
            OVRLipSync.Viseme.aa => Aa,
            OVRLipSync.Viseme.ih => Ih,
            OVRLipSync.Viseme.ou => Ou,
            OVRLipSync.Viseme.E => Ee,
            OVRLipSync.Viseme.oh => Oh,
            OVRLipSync.Viseme.sil => Neutral,
            _ => Neutral
        };
    }
    [Button]
    public void ShowAnger()
    {
        Show(ExpressionKey.Angry);
    }




    public enum AvatarType
    {
        VRM,
        FBX_Human,
        FBX_Pokemon,
    }
}


